home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d7 / jmodm308.arc / JMODEM_A.C < prev    next >
Text File  |  1991-01-02  |  36KB  |  571 lines

  1. /****************************************************************************/
  2. /*    FILE JMODEM_A.C                                                       */
  3. /*                                                                          */
  4. /*    The JMODEM protocol            MicroSoft (r)  'C' V5.1                */
  5. /*    Created 03-FEB-1990            Richard B. Johnson                     */
  6. /*                                   405 Broughton Drive                    */
  7. /*                                   Beverly, Massachusetts 01915           */
  8. /*                                   BBS (508) 922-3166                     */
  9. /*                                                                          */
  10. /*    An external protocol for high-speed data transmission.                */
  11. /*                                                                          */
  12. /*    This is the MAIN module                                               */
  13. /*    The required modules are:                                             */
  14. /*    JMODEM.H    (function prototypes and structures)                      */
  15. /*    UART.H      (8250 UART parameters)                                    */
  16. /*    SCREEN.H    (function protypes and structures for the screen)         */
  17. /*    JMODEM_A.C  (this module)                                             */
  18. /*    JMODEM_B.C  (memory allocation and input parsing)                     */
  19. /*    JMODEM_C.C  (all file I/O)                                            */
  20. /*    JMODEM_D.C  (encode/decode and CRC routines)                          */
  21. /*    JMODEM_E.C  (communications I/O routines)                             */
  22. /*    JMODEM_F.C  (the screen I/O routines)                                 */
  23. /*    JMODEM.     (The MAKE file )                                          */
  24. /*                                                                          */
  25. /*    This program requires about 67k of free RAM to execute properly.      */
  26. /*    If you have 66k or less, it will execute, but the screens will        */
  27. /*    not be written or replaced properly. If you have only 64k, the        */
  28. /*    program will exit with an error message.                              */
  29. /*                                                                          */
  30. /*    Revision History:                                                     */
  31. /*    V3.00   Beta test                  11-FEB-1990   Richard B. Johnson   */
  32. /*    V3.01   First release              18-FEB-1990   Richard B. Johnson   */
  33. /*    V3.02   Revised                    19-FEB-1990   Richard B. Johnson   */
  34. /*                                                                          */
  35. /*      (1)   A bug in MicroSoft _calloc()  allocates overlapping           */
  36. /*            buffers so data files were getting corrupted. I had           */
  37. /*            used both _calloc() and _malloc() at the same time and        */
  38. /*            they didn't like it. I changed the memory allocation          */
  39. /*            to _malloc() only and it seems to work okay.                  */
  40. /*                                                                          */
  41. /*      (2)   While debugging, I found some structures I didn't need and    */
  42. /*            removed them. Changed some code to accommodate.               */
  43. /*                                                                          */
  44. /*      (3)   Added a file-size during downloads.                           */
  45. /*                                                                          */
  46. /*      (4)   Changed code in the data encoding (compression) routine       */
  47. /*            in an attempt to speed it up.                                 */
  48. /*                                                                          */
  49. /*    V3.03   Revised                   20-FEB-1990  Richard B. Johnson     */
  50. /*                                                                          */
  51. /*      (5)   Fixed bug in compression routine where the loop wasn't        */
  52. /*            terminating properly, adding random characters. Bug was       */
  53. /*            created during V3.02 change.                                  */
  54. /*                                                                          */
  55. /*    V3.04   Revised                   27-FEB-1990  Richard B. Johnson     */
  56. /*                                                                          */
  57. /*      (1)   Modified the block-size routine and the receive-block         */
  58. /*            routine in an attempt to improve the noise immunity.          */
  59. /*            Does not abort even if you whistle into the telephone         */
  60. /*            during uploads and downloads. Waits 5 seconds to clear        */
  61. /*            the interrupt buffer when a bad block-size is received.       */
  62. /*                                                                          */
  63. /*      (2)   Added a 1/2 second wait for modem status when opening         */
  64. /*            channel. This might accommodate slow modems response to       */
  65. /*            RTS.                                                          */
  66. /*                                                                          */
  67. /*    V3.05   Revised                   22-MAR-1990  Richard B. Johnson     */
  68. /*                                                                          */
  69. /*      (1)   Removed _sprintf() runtime library calls to shorten           */
  70. /*            the code. Saved about 4k.                                     */
  71. /*                                                                          */
  72. /*      (2)   Removed extra spaces in the signon-logo to shorten            */
  73. /*            the program size.                                             */
  74. /*                                                                          */
  75. /*      (3)   Changed the method of creating a fixed-length string          */
  76. /*            for both the block size and cps numbers which saved about     */
  77. /*            800 bytes of program size.                                    */
  78. /*                                                                          */
  79. /*      (4)   Changed numerous array indexes in JMODEM_F.C to pointers      */
  80. /*            to reduce code size. Saved a few hundred bytes and should     */
  81. /*            improve speed of screen output.                               */
  82. /*                                                                          */
  83. /*      (5)   Created a local _puts() routine which saved over 6k from the  */
  84. /*            MicroSoft C runtime library version. (JMODEM_F.C)             */
  85. /*                                                                          */
  86. /*    V3.06   Revised                   07-APR-1990  Richard B. Johnson     */
  87. /*                                                                          */
  88. /*      (1)   Put the filename text into the syst structure as a pointer    */
  89. /*            to char. This allowed me to save 56 bytes of code and now     */
  90. /*            only two parameters are passed to the _screen() function.     */
  91. /*                                                                          */
  92. /*      (2)   Modified the syst structure and supporting code.              */
  93. /*                                                                          */
  94. /*      (3)   Moved all external data and functions to the JMODEM.H file.   */
  95. /*                                                                          */
  96. /*      (4)   Moved _disp() "usage" module to JMODEM_F.C                    */
  97. /*                                                                          */
  98. /*      (5)   Changed arrays in JMODEM_B.C to pointers to reduce code-      */
  99. /*            size. Eliminated _strcpy() from the command-line parsing      */
  100. /*            routines. Brought the code-size to less than 12,000 bytes.    */
  101. /*                                                                          */
  102. /*      (6)   Reduced the code-size in the _encode(), _decode(), and        */
  103. /*            _crc() routines in JMODEM_D.C. Removed shifts to improve      */
  104. /*            speed and replaced the shifts with pointers for altering      */
  105. /*            portions of the strings.                                      */
  106. /*                                                                          */
  107. /*      (7)   Made a _cancel() routine in JMODEM_A.C to send ^Xes upon      */
  108. /*            abort.                                                        */
  109. /*                                                                          */
  110. /*      (8)   Removed the bit being set "OUT 1" via the modem-control       */
  111. /*            register in the "open" routine in JMODEM_E.C. This was        */
  112. /*            causing some internal modems to lock up as they use this      */
  113. /*            bit for something. "OUT 2" is used to enable IRQ on most      */
  114. /*            clone RS-232 boards and modems. The Heathkit HZ-100 boards    */
  115. /*            will probably not work anymore because they use "OUT 1".      */
  116. /*                                                                          */
  117. /*                                                                          */
  118. /*    V3.07   Revised                   03-MAY-1990  Richard B. Johnson     */
  119. /*                                                                          */
  120. /*      (1)   Rewrote code to remove the requirement for a file buffer.     */
  121. /*            This means that this buffer does not need to be allocated,    */
  122. /*            saving about 8k of RAM at run-time.  ( JMODEM_A.C )           */
  123. /*                                                                          */
  124. /*            Program now only requires 52k of free RAM to execute okay.    */
  125. /*                                                                          */
  126. /*      (2)   Changed the header file, JMODEM.H, and function calling       */
  127. /*            procedures to file_io() and screen() to allow variable-       */
  128. /*            length parameter-lists. This eliminates the requirement       */
  129. /*            to pass a NULL as a place-holder on procedures that don't     */
  130. /*            always require all possible parameters to be passed. This     */
  131. /*            saved about 50 bytes of code.                                 */
  132. /*                                                                          */
  133. /*      (3)   Changed the "Usage" prompt and code to reduce program size.   */
  134. /*            Saved about 60 bytes.                                         */
  135. /*                                                                          */
  136. /*      (4)   Changed keyboard break interrupt in JMODEM_E.C so it sets     */
  137. /*            the global timer to zero as well as setting the abort flag.   */
  138. /*                                                                          */
  139. /*    V3.08   Revised                   01-DEC-1991  Richard B. Johnson     */
  140. /*                                                                          */
  141. /*      (1)   Changed the code to compile without warning errors when       */
  142. /*            using Microsoft Version 6.0. They saw fit to change the       */
  143. /*            ANSI standards for declaring objects passed to functions.     */
  144. /*            The new "standards" were called to my attention by            */
  145. /*            Jeff Jevnisek who provided modified source.                   */
  146. /*                                                                          */
  147. /*      (2)   Changed the method of determining a memory allocation         */
  148. /*            failure. The code used to check for a NULL pointer returned   */
  149. /*            from _malloc() if memory was not available. Microsoft does    */
  150. /*            not allow NULL to be used for that anymore! Instead I have    */
  151. /*            to either use a cast or check for (!ptr). I chose the latter. */
  152. /*                                                                          */
  153. /*                                                                          */
  154. /****************************************************************************/
  155. #include <stdlib.h>                     /* Used for _free()                 */
  156. #include <stdio.h>                      /* Used for NULL value              */
  157. #include <string.h>                     /* Used for _memcpy()               */
  158. #include <time.h>                       /* Used for absolute time           */
  159. #include "jmodem.h"                     /* JMODEM primatives                */
  160. /****************************************************************************/
  161. /*                   Global pointers and allocation                         */
  162. /****************************************************************************/
  163. word user_abort = 0;                    /* Global user abort flag           */
  164. byte *int_buffer;                       /* Pointer to interrupt buffer      */
  165. SYS syst;                               /* Structure for JMODEM status      */
  166. /****************************************************************************/
  167. /*                               C O D E                                    */
  168. /****************************************************************************/
  169. short main (short argc,  char *argv[])
  170. {
  171.     byte *in_buffer;                      /* Pointer to input buffer        */
  172.     byte *out_buffer;                     /* Pointer to output buffer       */
  173.     byte *comp_buffer;                    /* Pointer to compression buffer  */
  174.     register byte *io_ptr;                /* Select buffers to use for I/O  */
  175.     register JBUF *buff;                  /* A pointer for the JMODEM block */
  176.     byte *file_name;                      /* Filename                       */
  177.     byte function;                        /* Receive, Transmit              */
  178.     time_t start;                         /* Start time                     */
  179.     time_t finish;                        /* End time                       */
  180. #ifdef FTIME                              /* Floating point timer           */
  181.     double dat_tmp;                       /* Temporary variable for time    */
  182. #endif
  183.     word status=0;                        /* TX and RX status               */
  184.     word tries;                           /* Attempts to send a file        */
  185.     word cmp_size;                        /* Size after compression         */
  186.     word data_written;                    /* Data written to the file       */
  187.     word data_read;                       /* Data read from the file        */
  188.     short handle;                         /* For file I/O                   */
  189.  
  190.     if (!(file_name = get_inp (argc, argv))) /* Get file name               */
  191.     {
  192.         disp();                              /* Display usage message       */
  193.         return JM_FNF;
  194.     }
  195.     if (!(function = get_fun (argc, argv)))  /* Get function 'R' or 'S'     */
  196.     {
  197.         disp();                              /* Display usage message       */
  198.         return JM_CMD;
  199.     }
  200.     if (!(port = get_port (argc, argv)))     /* Get port '1 to 4 '          */
  201.     {
  202.         disp();                              /* Display usage message       */
  203.         return JM_CMD;
  204.     }
  205. /****************************************************************************/
  206. /*                          Allocate buffers                                */
  207. /****************************************************************************/
  208.     in_buffer = allocate_memory(DAT_LEN);  /* Get some memory for input     */
  209.     if (!in_buffer)
  210.         return JM_MEM;                     /* No memory available           */
  211.     out_buffer = allocate_memory(DAT_LEN); /* Get some memory for output    */
  212.     if (!out_buffer)
  213.         return JM_MEM;                     /* No memory available           */
  214.     comp_buffer=allocate_memory(DAT_LEN);  /* Get memory for compression    */
  215.     if (!comp_buffer)
  216.         return JM_MEM;                     /* No memory available           */
  217.     int_buffer =allocate_memory(DAT_LEN);  /* Memory for interrupt buffer   */
  218.     if (!int_buffer)
  219.         return JM_MEM;                     /* No memory available           */
  220. /****************************************************************************/
  221.     screen (SCR_SGN);                      /* Write signon screen           */
  222.     syst.s_len = BLK_SIZ;                  /* Set beginning block size      */
  223.     syst.s_byt = 0;                        /* Set bytes handled             */
  224.     syst.s_blk = 0;                        /* Starting block                */
  225.     syst.s_sta = okay;                     /* Starting status               */
  226.     switch(function)                       /* Functions are TX and RX       */
  227.     {
  228. /****************************************************************************/
  229. /*                          Receive JMODEM file                             */
  230. /****************************************************************************/
  231.     case 'R':
  232.         {
  233.             if (!file_io(CREATE, &handle, file_name) )
  234.             {
  235.                 buff = (JBUF *) in_buffer;           /* Assign type JBUF    */
  236.                 open_chan(port);                     /* Open com channel    */
  237.                 screen (SCR_STA);                    /* Write status block  */
  238.                 status = rx_sync();                  /* Synchronize         */
  239.                 if (!status)
  240.                     screen (SCR_SYR);
  241.                 data_written = 0xFFFF;
  242.                 tries = 10;                          /* Attempts to receive */
  243.                 while (    (data_written)            /* Write file okay     */
  244.                         && (!user_abort )            /* No break key        */
  245.                         && (!status     )            /* Recev block okay    */
  246.                         && (tries--)    )            /* 10 retries          */
  247.                 {
  248.                     time(&start);                    /* Get starting time   */
  249.                     screen (SCR_SYS,&syst);          /* Show status block   */
  250.                     status = recv_blk (              /* Receive data-block  */
  251.                              &syst.s_len,            /* Block length        */
  252.                              in_buffer);             /* Input buffer        */
  253.                     if (status)                      /* If bad              */
  254.                         break;                       /* Abort the WHILE     */
  255.                     if( (!(calc_crc( GET_CRC,        /* Calculate CRC       */
  256.                           syst.s_len,                /* Amount to check     */
  257.                           in_buffer) ))              /* Receiver buffer     */
  258.                       && ( buff->blk_num ==          /* Check block also    */
  259.                          (byte)
  260.                          (syst.s_blk +1)))           /* Block number        */
  261.                     {
  262.                         syst.s_sta = okay;           /* Text pointer        */
  263.                         tries=10;                    /* Reset count         */
  264.                         syst.s_len -= OVRHD;         /* Subtract overhead   */
  265.                         *out_buffer = ACK;           /* Good                */
  266.                         write_chan(1,out_buffer);    /* Send the ACK        */
  267.                         io_ptr = &buff->blk_dat;     /* Assume normal data  */
  268.  
  269.                         if ( (buff->blk_typ & COMP) == COMP)
  270.                         {                            /* If data compressed  */
  271.                              syst.s_len = decode (   /* Decode the data     */
  272.                                       syst.s_len,    /* Data-block length   */
  273.                                      &buff->blk_dat, /* Where to start      */
  274.                                      comp_buffer);   /* Where to put data   */
  275.                              io_ptr = comp_buffer;   /* Point to data       */
  276.                         }
  277.                         data_written = file_io(WRITE, /* Write to file      */
  278.                                          &handle,     /* File handle        */
  279.                                          io_ptr ,     /* Where data is      */
  280.                                          syst.s_len); /* Amount to write    */
  281.                         syst.s_byt += data_written;   /* Total bytes        */
  282.                         syst.s_blk++;                 /* Block number       */
  283.                         time(&finish);                /* Get end time       */
  284.                         if (finish - start)           /* Check div/0        */
  285.                         {
  286. #ifdef FTIME
  287.                             dat_tmp = (double) data_written;
  288.                             syst.s_cps = (short) (dat_tmp /
  289.                                                difftime(finish,start));
  290. #else
  291.                             syst.s_cps = (short)      /* Calc Block CPS     */
  292.                             (data_written / (finish - start) );
  293. #endif
  294.                         }
  295.                                                        /* Check end-of-file */
  296.                         if ( (buff->blk_typ & EOF_) == EOF_)
  297.                         {
  298.                             file_io(CLOSE,&handle);   /* Close file         */
  299.                             close_chan(port);         /* Close the port     */
  300.                             status = JM_NRM;          /* Set status         */
  301.                             goto cleanup;             /* exit routine       */
  302.                         }
  303.                     }
  304.                     else
  305.                     {
  306.                         *out_buffer = NAK;            /* Bad block          */
  307.                         syst.s_sta = retry;           /* Char pointer       */
  308.                         write_chan(1,out_buffer);     /* Send the NAK       */
  309.                      }
  310.                 }
  311.                 close_chan(port);                     /* Aborted            */
  312.                 file_io( DELETE, &handle, file_name); /* Delete bad file    */
  313.                 status = JM_ABT;
  314.                 break;                                /* Exit if() {}       */
  315.             }
  316.             else                                      /* Can't create file  */
  317.             {
  318.                 status = JM_CRE;
  319.                 break;                                /* Exit while() {}    */
  320.             }
  321.         }
  322. /****************************************************************************/
  323. /*                          Send JMODEM file                                */
  324. /****************************************************************************/
  325.     case 'S':   /* Send JMODEM file */
  326.         {
  327.             if (!file_io(OPEN_READ, &handle, file_name) )
  328.             {
  329.                 buff = (JBUF *)out_buffer;            /* Assign type JBUF   */
  330.                 syst.s_byt = 0;                       /* Restore byte count */
  331.                 open_chan(port);                      /* Open COM port      */
  332.                 screen (SCR_STA);                     /* Write status block */
  333.                 status = tx_sync();                   /* Synchronize        */
  334.                 if (!status)
  335.                     screen (SCR_SYT);
  336.                 while  ( (!user_abort)                /* Ctrl - break       */
  337.                        && (!status) )                 /* sent okay          */
  338.                 {
  339.                     time(&start);                     /* Get starting time  */
  340.                     data_read = file_io( READ,        /* Read a record      */
  341.                                       &handle,        /* File pointer       */
  342.                                       &buff->blk_dat, /* Where to put data  */
  343.                                       syst.s_len );   /* Amount to read     */
  344.                     if (!data_read)                   /* Past end of file   */
  345.                         break;
  346.                     syst.s_byt += (long) data_read;   /* Running count      */
  347.                     screen (SCR_SYS,&syst);           /* Show status block  */
  348.                     buff->blk_num = (byte)
  349.                                      ++syst.s_blk;    /* Block number       */
  350.                     buff->blk_typ = NORM;             /* Assume Normal      */
  351.                     buff->len = (data_read+OVRHD);    /* Length of block    */
  352.                     if (data_read != syst.s_len)      /* Less than request  */
  353.                         buff->blk_typ |= EOF_;        /* Its end of file    */
  354.                     cmp_size = encode (data_read,     /* Encode size        */
  355.                                       &buff->blk_dat, /* Source             */
  356.                                       comp_buffer);   /* Destination        */
  357.                     if ( cmp_size  < data_read  )     /* If compressed      */
  358.                     {
  359.                         buff->len = (cmp_size+OVRHD); /* Length of block    */
  360.                         buff->blk_typ |= COMP;        /* Show compressed    */
  361.                         memcpy (&buff->blk_dat,       /* Start of data      */
  362.                                    comp_buffer,       /* Copy from here     */
  363.                                    cmp_size);         /* This much          */
  364.                     }
  365.                     calc_crc(SET_CRC,                 /* Calculate CRC      */
  366.                             buff->len ,               /* Length of block    */
  367.                             out_buffer);              /* Where data is      */
  368.                     status = send_blk(                /* Send the block     */
  369.                              buff->len,               /* Block length       */
  370.                              &syst,                   /* Read block ptr.    */
  371.                              out_buffer);             /* Buffer pointer     */
  372.                     time(&finish);                    /* Get end time       */
  373.                     if (finish - start)               /* Check div/0        */
  374.                     {
  375. #ifdef FTIME
  376.                         dat_tmp = (double) data_read;
  377.                         syst.s_cps = (short) (dat_tmp /
  378.                                      difftime(finish,start));
  379. #else
  380.                         syst.s_cps = (short)          /* Calc Block CPS     */
  381.                         (data_read / (finish - start) );
  382. #endif
  383.                     }
  384.                     if ( buff->blk_typ == EOF_)       /* Last record        */
  385.                         break;
  386.                 }
  387.                 syst.s_sta = done;                    /* Assume normal      */
  388.                 if (status)
  389.                 {
  390.                     cancel();                         /* Send ^Xes          */
  391.                     syst.s_sta = abrt;                /* Was aborted        */
  392.                 }
  393.                 close_chan(port);                     /* Close the port     */
  394.                 file_io(CLOSE, &handle);              /* Close the file     */
  395.                 screen (SCR_SYS,&syst);               /* Show status block  */
  396.             }
  397.             else                                      /* File not found     */
  398.             {
  399.                 status = JM_FNF;
  400.             }
  401.         break;                                        /*   End of CASE 'S'  */
  402.         }
  403.     }
  404.     cleanup:
  405.     free (in_buffer);                                 /* Free  buffers      */
  406.     free (out_buffer);
  407.     free (comp_buffer);
  408.                               /* Two-second timer to display error messages */
  409.     if (status != JM_NRM)
  410.     {
  411.         time(&finish);                               /* Get system clock    */
  412.         finish += 2;                                 /* Add two seconds     */
  413.         start = 0;
  414.         while ( finish > start )                     /* Wait until the same */
  415.             time(&start);
  416.     }
  417.     screen (SCR_END);                                /* Clear the screen    */
  418.     return status;                                   /* Normal exit         */
  419. }
  420. /****************************************************************************/
  421. /*                          Send the JMODEM block                           */
  422. /****************************************************************************/
  423. word send_blk (word blk_len,
  424.                register SYS *sys_ptr,
  425.                register byte *buffer)
  426. {
  427.     byte ack_buf;                         /* Buffer for ACK/NAK             */
  428.     word tries = 10;                      /* Attempts to send the block     */
  429.     while ((tries--) && (!user_abort))
  430.     {
  431.         write_chan(blk_len,buffer);       /* Send the JMODEM block          */
  432.         flush();                          /* Clear back channel noise       */
  433.         do
  434.         {
  435.             ack_buf = (char) 0x00;        /* Clear the return buffer        */
  436.             read_chan(1,&ack_buf);        /* Receive a response             */
  437.         } while ( (ack_buf != ACK)        /* Stay in loop until we          */
  438.                && (ack_buf != CAN)        /*  ... get something useful      */
  439.                && (ack_buf != NAK)        /* This helps re-sync in noise    */
  440.                && (ack_buf == (char) 0x00)
  441.                && (!user_abort) );
  442.  
  443.         if ( (ack_buf == CAN)
  444.            || user_abort )                /* Check for an abort             */
  445.             break;                        /* User aborted                   */
  446.         if (ack_buf == ACK)               /* If good block                  */
  447.         {
  448.             if (tries == 9)               /* If no retries                  */
  449.             {
  450.                 sys_ptr->s_len += 512;    /* Increase block-size            */
  451.                 if (sys_ptr->s_len > DAT_MAX) /* If too large               */
  452.                     sys_ptr->s_len = DAT_MAX;
  453.             }
  454.             else
  455.             {
  456.                 tries = 9 - tries;        /* Use for divisor                */
  457.                 sys_ptr->s_len =          /* Update block length            */
  458.                 sys_ptr->s_len / tries;   /* Div block size                 */
  459.             if (sys_ptr->s_len < 0x40)    /* If less than minimum           */
  460.                 sys_ptr->s_len = 0x40;    /* Set to minimum                 */
  461.             }
  462.         sys_ptr->s_sta = okay;            /* Show status is okay            */
  463.         return JM_NRM;                    /* Show good                      */
  464.         }
  465.     sys_ptr->s_sta = retry;               /* Show a retry                   */
  466.     screen (SCR_SYS, sys_ptr);            /* Write to screen                */
  467.     }
  468.     cancel();                             /* Send cancel (^Xes)             */
  469.     return JM_ABT;                        /* Abort local program            */
  470. }
  471. /****************************************************************************/
  472. /*                        Receive the JMODEM block                          */
  473. /****************************************************************************/
  474. word recv_blk (word *blk_len,
  475.                register byte *buffer)
  476. {
  477.     register JBUF *buff;                  /* Pointer type JBUF              */
  478.     byte nak_buf;                         /* Buffer for ACK/NAK             */
  479.     word tries = 10;                      /* Attempts to receive the block  */
  480.     word ret_val;                         /* Block length returned          */
  481.     buff = (JBUF * )buffer;               /* Assign pointer type JBUF       */
  482.  
  483.     while ((tries--) && (!user_abort))
  484.     {
  485.         ret_val = read_chan(2,buffer);    /* Receive the block size         */
  486.         if (ret_val == 2)                 /* If we received the length      */
  487.         {
  488.             *blk_len = buff->len;         /* So caller knows size           */
  489.             if (*blk_len > DAT_LEN)       /* If way out of line             */
  490.                 break;                    /* NAK it                         */
  491.             ret_val = read_chan(          /* Get more data                  */
  492.                       (*blk_len)-2 ,      /* Size to read                   */
  493.                       &buff->blk_typ);    /* Where to put it                */
  494.             if (ret_val == (*blk_len)-2)  /* If we got what we requested    */
  495.                 return JM_NRM;
  496.         }
  497.     if (buff->blk_typ == CAN)             /* If transmitter sent ^Xes       */
  498.         break;                            /* The other side has aborted     */
  499.     read_chan (DAT_LEN,buffer);           /* Make sure other end stops      */
  500.     nak_buf = NAK;                        /* Get a NAK                      */
  501.     write_chan(1,&nak_buf);               /* Send to remote                 */
  502.     flush();                              /* Flush the buffer               */
  503.     }
  504.     cancel();                             /* Send cancel (^Xes)             */
  505.     return JM_ABT;                        /* Abort local program            */
  506. }
  507. /****************************************************************************/
  508. /*                         Synchronize during receive                       */
  509. /****************************************************************************/
  510. word rx_sync()
  511. {
  512.     byte ack_nak;                         /* Single byte buffer for ACK/NAK */
  513.     flush();                              /* Clear the interrupt buffer     */
  514.     while (!user_abort)
  515.     {
  516.         ack_nak = (char) 0x00;            /* Clear the buffer               */
  517.         read_chan(1,&ack_nak);            /* Receive ACK, NAK, or SYN       */
  518.         if (ack_nak == CAN)               /* If a ^X                        */
  519.             break;
  520.         if ( ack_nak == ACK )             /* If a good response             */
  521.             return JM_NRM;                /* Show handshake                 */
  522.         if ( ack_nak == NAK )             /* If a good response             */
  523.         {
  524.             ack_nak = ACK;
  525.             write_chan(1,&ack_nak);       /* Send a ACK response            */
  526.             return JM_NRM;
  527.          }
  528.          ack_nak = NAK;
  529.          write_chan(1,&ack_nak);          /* Keep sending NAKs              */
  530.     }
  531.     cancel();                             /* Send cancel (^Xes)             */
  532.     return JM_ABT;
  533. }
  534. /****************************************************************************/
  535. /*                           Send ^Xes to cancel                            */
  536. /****************************************************************************/
  537. void cancel()
  538. {
  539.     byte buffer = CAN;
  540.     short xes = 6;
  541.  
  542.     user_abort=0;                         /* Reset flag so write_chan works */
  543.     while(xes--)
  544.         write_chan(1,&buffer);
  545. }
  546. /****************************************************************************/
  547. /*                         Synchronize during transmit                      */
  548. /****************************************************************************/
  549. word tx_sync()
  550. {
  551.     word ret_val;
  552.     ret_val = rx_sync();                /* Call same routine for receive    */
  553.     if (!ret_val)                       /* If success                       */
  554.     {
  555.         flush();                        /* Flush the input buffer           */
  556.         timer = 5;                      /* 5 timer-ticks to wait            */
  557.         while (timer);                  /* Wait for timer                   */
  558.     }
  559.     return ret_val;                     /* Return status                    */
  560. }
  561. /****************************************************************************/
  562. /*     Dummy _setenvp procedure to replace the large library module         */
  563. /****************************************************************************/
  564. #ifdef NOENV                            /* If a compiler command            */
  565. void _setenvp(void);                    /* Dummy routine prototype          */
  566. void _setenvp()                         /* Dummy routine                    */
  567. {}
  568. #endif
  569. /****************************************************************************/
  570. /************************ E N D  O F   M O D U L E **************************/
  571.